from __future__ import annotations

import os
import re
from typing import Set, Dict

from .base import BaseLanguageDependencyStrategy
from ...utils_module.language_utils import language_to_extensions


class SwiftDependencyStrategy(BaseLanguageDependencyStrategy):
    LANGUAGE = 'swift'

    def __init__(self, logger=None):
        super().__init__(logger)
        self._import_patterns = [
            re.compile(r'^import\s+([\w\.]+)', re.MULTILINE),
            re.compile(r'^@_exported\s+import\s+([\w\.]+)', re.MULTILINE),
            re.compile(r'^@testable\s+import\s+([\w\.]+)', re.MULTILINE),
        ]

    def extract_imports(self, content: str) -> Set[str]:
        imports: Set[str] = set()
        for pattern in self._import_patterns:
            imports.update(pattern.findall(content))
        return imports

    def resolve_import(
        self,
        import_name: str,
        source_file: str,
        module_to_files: Dict[str, Set[str]],
    ) -> Set[str]:
        resolved: Set[str] = set()
        source_dir = os.path.dirname(source_file)

        if import_name in module_to_files:
            resolved.update(module_to_files[import_name])

        for candidate in self._generate_possible_paths(import_name, source_dir):
            if os.path.exists(candidate):
                resolved.add(os.path.abspath(candidate))

        return resolved

    def extract_module_name(self, file_path: str):
        file_name = os.path.basename(file_path)
        file_stem, _ = os.path.splitext(file_name)
        return file_stem

    def _generate_possible_paths(self, import_name: str, base_dir: str):
        swift_exts = set(language_to_extensions('swift'))
        path_parts = import_name.replace('.', os.sep).split(os.sep)

        for ext in swift_exts:
            yield os.path.join(base_dir, *path_parts) + ext

        dir_path = os.path.join(base_dir, *path_parts)
        if os.path.isdir(dir_path):
            for entry in os.listdir(dir_path):
                if any(entry.endswith(ext) for ext in swift_exts):
                    yield os.path.join(dir_path, entry)
